package com.neuralnoise.geo;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;

import com.google.code.geocoder.Geocoder;
import com.google.code.geocoder.GeocoderRequestBuilder;
import com.google.code.geocoder.model.GeocodeResponse;
import com.google.code.geocoder.model.GeocoderGeometry;
import com.google.code.geocoder.model.GeocoderRequest;
import com.google.code.geocoder.model.GeocoderResult;
import com.google.code.geocoder.model.LatLng;
import com.neuralnoise.GeoDB;
import com.neuralnoise.geo.osm.Address;
import com.neuralnoise.geo.osm.JsonNominatimClient;
import com.neuralnoise.hibernate.geo.GeoLocation;
import com.neuralnoise.hibernate.geo.GeoLocationId;

public class GeoUtils {
	
	public enum ServiceType { GOOGLE, OSM };
	
	private GeoUtils() { }
	
	public static GeoLocation askOSM(ServiceType service, String addr, String language) throws IOException {
        HttpClient httpClient = new DefaultHttpClient();
        String email = "p.minervini@gmail.com";
        JsonNominatimClient nominatimClient = new JsonNominatimClient(httpClient, email, null, false, true);
        List<Address> addresses = nominatimClient.search(addr);
		GeoLocation location = null;
        Iterator<Address> it = addresses.iterator();
		if (it.hasNext()) {
			Address address = it.next();
			String formatted = address.getDisplayName();
			double lati = address.getLatitude();
			double longi = address.getLongitude();
			GeoLocationId gid = new GeoLocationId(service, addr, language);
			location = new GeoLocation(gid, formatted, 0.0, lati, longi);
		}
		return location;
	}
	
	public static GeoLocation askGoogle(ServiceType service, String address, String language) {
		
		if (address == null || address.equals(""))
			return null;
		
		Geocoder geocoder = new Geocoder();
		GeocoderRequestBuilder builder = new GeocoderRequestBuilder().setAddress(address).setLanguage(language);

		System.out.println("Address: " + address + ", Language: " + language);
		
		GeocoderRequest request = builder.getGeocoderRequest();
		GeocodeResponse response = geocoder.geocode(request);
		GeoLocation location = null;
		Iterator<GeocoderResult> it = response.getResults().iterator();
		if (it.hasNext()) {
			GeocoderResult result = it.next();
			GeocoderGeometry geometry = result.getGeometry();
			LatLng latlng = geometry.getLocation();
			String formatted = result.getFormattedAddress();
			
			double lati = Double.NEGATIVE_INFINITY;
			if (latlng.getLat() != null) 
				lati = latlng.getLat().doubleValue();
			
			double longi = Double.NEGATIVE_INFINITY;
			if (latlng.getLng() != null)
				longi = latlng.getLng().doubleValue();	

			GeoLocationId gid = new GeoLocationId(service, address, language);
			location = new GeoLocation(gid, formatted, 0.0, lati, longi);
		}
		return location;
	}
	
	public static GeoLocation findAddLocation(ServiceType service, String address, String language) throws IOException {
		GeoLocation location = GeoDB.getLocation(service, address, language);
		if (location == null) {
			switch (service) {
			case GOOGLE: {
				location = askGoogle(service, address, language);
			} break;
			case OSM: {
				location = askOSM(service, address, language);
			} break;
			default: {
				throw new IllegalStateException(service + " not supported");
			}
			}
			
			if (location != null)
				GeoDB.addLocation(location);
		}
		return location;
	}
	
}
